'use strict';

import { Service } from 'egg';
import {join} from "path";
import {createReadStream,createWriteStream} from "mz/fs"
import {pump} from "mz-modules"

import {existsSync,mkdirSync,statSync,unlinkSync} from "fs";
import {Op} from 'sequelize';
/**
 * 通用服务类
 * 通用逻辑处理
 */
export default class CommonService extends Service{
    /**
     * 查询一个结果的通用处理过程
     * 参数：
     *  condition 检索条件
     * 输出：
     * {Object} data 查询结果数据结构
     * 过程：
     * 通过传入的模型名称，查询结果后去掉密码，格式化创建时间
     */
    async find_one(condition,model_name,key_id){
        const {ctx,app}=this;
        try {
            let result=await app.model[model_name].findOne({
                where:condition
            });
            result=JSON.parse(JSON.stringify(result));
            if(result&&result[key_id]){
                let obj={};
                for (const key in result) {
                    if (result.hasOwnProperty(key)) {
                        const element = result[key];
                        if(key.indexOf("password")==-1){
                            obj[key]=element;
                        }
                    }
                }
                obj['create_time']=ctx.helper.date_format(result['create_time'],'yyyy-MM-dd hh:mm:ss');
                console.log(obj);
                return obj;
            }
            return {};
        } catch (error) {
            console.log(error)
            return {};
        }
        
    }
    /**
     * 将文件移动到目标路径中
     * 参数：
     *  condition 检索条件
     * 输出：
     * {Object} data 查询结果数据结构
     * 过程：
     * 通过传入的file对象，以及目标文件夹，
     * 创建stream读写流将文件复制过去
     * 复制成功返回可访问的路径
     */
    async to_target_path(file,floder_path){
        const {ctx,app}=this;
        try {
            let baseDir=app.config.baseDir;
            let filename : string = Date.now() + '' + ctx.helper.parse_int(Math.random() * 10000)+file.filename.toLowerCase();

            let userDirPath=join(baseDir,'app/public/',floder_path);
            if(!existsSync(userDirPath)) {mkdirSync(userDirPath)};
            const targetPath = join(userDirPath, filename);
            const source = createReadStream(file.filepath);
            const target = createWriteStream(targetPath);
            await pump(source, target);
            let accessUrl : string =app.config.accessPath+floder_path+filename;
            return accessUrl;
        } catch (error) {
            console.log("to error: ",error);
        }
        return null;
    }
    /**
     * 通过访问路径删除文件
     * 参数：
     *  access_url 访问路径
     * 输出：
     *    void
     * 过程：
     * 如果访问路径存在，则获取访问路径public后面的路径字符串，
     * 拼接文件的原始路径，得到原始路径后判断文件是否存在删除文件
     */
    un_link_file(access_url){
        const {app}=this;
        let baseDir=app.config.baseDir;
        let origin_url="";
        if(access_url){
            if(access_url.indexOf("public")>-1){
                access_url=access_url.split("public/")[1];
            }
            origin_url=join(baseDir,'app/public',access_url);
        }
        if(origin_url){
            if(existsSync(origin_url)&&statSync(origin_url).isFile()){
                unlinkSync(origin_url);
            }
        }
    }
    /**
     * 分页查询所有数据(通用)
     * 参数：
     *  condition 检索条件
     * 输出：
     * {Number} code 返回状态码 0失败  200成功
     * {String} message 返回状态对应提示消息
     * {Object[]} data 分类列表
     * 过程：
     *  构建分页查询条件，
     *  分页查询数据，遍历结果集处理创建时间处理password等信息，返回结果
     */
    async find_and_count_all(condition,order_condition,page,model_name,attributes ?){
        const {ctx,app}=this;
        try {
            let page_param=ctx.helper.page_param(page);
            let obj={
                where:condition,
                order:order_condition,
                limit:page_param.page_size,
                offset:page_param.offset
            }
            if(attributes && attributes.length>0){
                obj['attributes']=attributes
            }
            let result=await app.model[model_name].findAndCountAll(obj);
            console.log(result)
            if(result&&result.rows&&result.rows.length>0){
                result=JSON.parse(JSON.stringify(result));
                result.rows.map(ele=>{
                    if(ele['create_time']){
                        ele['create_time']=ctx.helper.date_format(ele['create_time'],'yyyy-MM-dd hh:mm:ss');
                    }
                    if(ele['password']){
                        delete ele['password']
                    }
                })
            }
            return ctx.helper.success_result("操作成功",ctx.helper.page_result(result,page_param.page_size))
        } catch (error) {
            console.log(error)
            return ctx.helper.error_result("查询出错");
        }
    }
    async find_all(condition,order_condition,model_name){
        const {ctx,app}=this;
        try {
            let result=await app.model[model_name].findAll({
                where:condition,
                order:order_condition,
            });
            if(result&&result.length>0){
                result=JSON.parse(JSON.stringify(result));
                result.map(ele=>{
                    ele['create_time']=ctx.helper.date_format(ele['create_time'],'yyyy-MM-dd hh:mm:ss');
                })
            }
            return ctx.helper.success_result("操作成功",result)
        } catch (error) {
            return ctx.helper.error_result("查询出错");
        }
    }
    /**
     * 
     * @param resources 
     * 获取资源列表数据
     * 将资源数据拆成包含两个元素的数组，第一存资源的简介，资源封面路径
     * 第二个存资源内容
     */
    get_resource_list(resources){
        let resource_list:object[]=[];
        const {ctx}=this;
        try {
            //console.log(resources);
            resource_list.push(
                {
                    resource_id:resources[0]?resources[0]['resource_id'] : '',
                    resourc_name:resources[0]?resources[0]['resource_name'] : '',
                    resource_content:resources[0]?resources[0]['resource_vedio'] : '',
                    resource_abstract:resources[0]?resources[0]['resource_abstract'] : '',
                    resource_url:resources[0]?resources[0]['resource_url'] : '',
                    create_time:resources[0] ? ctx.helper.date_format_basic(resources[0]['create_time']) : '',
                    type:resources[0] ? resources[0]['type'] : 0
                }
            )
            resource_list.push(
                {
                    resource_id:resources[0]?resources[0]['resource_id'] : '',
                    resourc_name: '',
                    resource_content:resources[0]?resources[0]['resource_content'] : '',
                    resource_abstract:'',
                    resource_url:'',
                    create_time:resources[0] ? ctx.helper.date_format_basic(resources[0]['create_time']) : ''
                }
            )
            return resource_list;
        } catch (error) {
            console.log(error);
        }
        return [];
    }
    /**
     * 
     * @param resources 
     * 设置资源，将拆成的两个资源数组，合成一个资源模型记录
     */
    async set_resource(resources,origin){
        const {app}=this;
        try {
            let resource={
                resource_name:resources[0] ? resources[0]['resource_name'] : '',
                resource_url:resources[0] ? resources[0]['resource_url'] : '',
                resource_vedio:resources[0]?JSON.stringify(resources[0]['resource_content']) : '',
                resource_abstract:resources[0] ? resources[0]['resource_abstract'] : '',
                resource_content:resources[1] && resources[1]['resource_content'] ?resources[1]['resource_content']:'', 
                ...origin
            }
            return await app.model.Resource.create(resource);; 
        } catch (error) {
            console.log(error)
        }
        return null
    }
    /**
     * 
     * @param resources 
     * @param product 
     * @param key 
     * 获取资源详情数据，包括资源封面资源简介，资源内容
     */
    get_resource_info(resources,product,key){
        product[key+'_img']=resources[0]['resource_url'];
        product[key+'_abstract']=resources[0]['resource_abstract'];
        product[key+'_content']=resources[0]['product_vedio'];
        return product;
    }
    /**
     * 
     * @param Model 
     * @param condition 
     * @param type 
     * @param key 
     * @param len 
     * 查询产品列表(包括解决方案列表)
     * 过程：
     *   关联类型，二级类型，资源等关联关系后，
     *   查询所有产品，查出后调用get_product_list返回结果
     */
    async product_list(Model,condition,type,key,len?:number){
        const {app}=this;
        const {Resource,Category,Sub}=app.model;
        try {
            let query_obj={
                where:condition,
                include:[{
                    model:Resource,
                    attributes:['resource_id','resource_abstract','resource_name','resource_url','resource_vedio'],
                    association:Model.hasMany(Resource,{foreignKey:"parent_id"}),
                    where:{
                        type
                    },
                    limit:1,
                    required:false
                },{
                    model:Category,
                    association:Model.belongsTo(Category,{foreignKey:'category_id'}),
                    attributes:['category_name'],
                    required:false
                },{
                    model:Sub,
                    association:Model.belongsTo(Sub,{foreignKey:'sub_id'}),
                    attributes:['sub_name'],
                    required:false
                }],
                order:[['create_time','DESC']]
            }
            if(len){
                query_obj['limit']=len
            }
            let result=await Model.findAll(query_obj)
            return this.get_product_list(result,key)
        } catch (error) {
            
        }
        return [];
    }
    /**
     * 
     * @param result 
     * @param key 
     * 获取产品列表
     * 根据传入的结果集遍历，对每个元素进行get_resource_info操作，即可获取产品详细信息
     * 将构建后的产品放入list集合返回结果
     */
    get_product_list(result,key){
        const{ctx}=this;
        let list:object[]=[];
        result=JSON.parse(JSON.stringify(result));
        result.forEach(ele=>{
            let product=ctx.helper.assign_basic({},ele);
            if(ele['resources']&&ele['resources'].length>0){
                product=ctx.service.common.get_resource_info(ele['resources'],product,key);
            }
            if(ele['category']){
                product['category_name']=ele['category']['category_name']
            }
            if(ele['sub']){
                product['sub_name']=ele['sub']['sub_name']
            }
            list.push(product);
        })
        return list;
    }
    /**
     * 
     * @param Model 
     * @param condition 
     * @param type 
     * 查询产品详情
     * 关联关系建立后，根据关联资源，构建资源列表数据
     * 返回结果
     */
    async product_info(Model,condition,type){
        const {ctx,app}=this;
        const {Resource,Category,Sub}=app.model;
        try {
            let result=await Model.findOne({
                where:condition,
                include:[{
                    model:Resource,
                    association:Model.hasMany(Resource,{foreignKey:"parent_id"}),
                    where:{
                        type:type
                    },
                    limit:1,
                    attributes:['resource_id','resource_abstract','resource_name','resource_url','resource_vedio','resource_content','parent_id','type'],
                },{
                    model:Category,
                    association:Model.belongsTo(Category,{foreignKey:'category_id'}),
                    attributes:['category_name']
                },{
                    model:Sub,
                    association:Model.belongsTo(Sub,{foreignKey:'sub_id'}),
                    attributes:['sub_name']
                }]
            })
            let list:object[]=[];
            let ele=JSON.parse(JSON.stringify(result));
            
            if(!ele){
                return []
            }
            let product=ctx.helper.assign_basic({},ele);
            product['resource_list']=[];
            if(ele['resources']&&ele['resources'].length>0){
                product['resource_list']=this.get_resource_list(ele['resources']);
            }
            if(ele['category']){
                product['category_name']=ele['category']['category_name']
            }
            if(ele['sub']){
                product['sub_name']=ele['sub']['sub_name']
            }
            list.push(product);
            return list;
        } catch (error) {
            console.log(error)
        }
        return [];
    }
    /**
     * 
     * @param Model 
     * @param query 
     * @param condition 
     * @param key 
     * 产品类型列表 已废弃
     */
    async product_cate_group(Model,query,condition,key){
        const{ctx,app}=this;
        try {
            const {Category,SubCategory,Sub} = app.model;
            let result=await Category.findAll({
                include:[
                    {
                        model:Model,
                        association:Category.hasMany(Model,{foreignKey:'category_id'}),
                        limit:parseInt(query.cur_index)
                    },{
                        model:SubCategory,
                        isAliased:true,
                        association:Category.hasMany(SubCategory,{foreignKey:'category_id'}),
                        include:[
                            {
                                model:Sub,
                                association:SubCategory.belongsTo(Sub,{foreignKey:'sub_id'}),
                                include:[{
                                    model:Model,
                                    association:Sub.hasMany(Model,{foreignKey:'sub_id'}),
                                    limit:1,
                                    required:false
                                }],
                                order:[['sort','DESC']],
                            }
                        ]
                    }
                ],
                where:condition,
                attributes:["category_id","category_name","create_time"],
                order:[['create_time','DESC']]
            })
            
            result=JSON.parse(JSON.stringify(result)); 
            let list:object[]=[];
            
            result.forEach(category => {
                let tmp=ctx.helper.assign_basic({},category);
                tmp['create_time']=ctx.helper.date_format_basic(category['create_time']);
                tmp['sub_list']=[];
                tmp['sub_have_'+key+"s"]=0


                if(category['sub_categories']&&category['sub_categories'].length>0){
                    category['sub_categories'].forEach(sub_cate=>{
                        let sub=ctx.helper.assign_basic({},sub_cate);
                        sub['sub_name']=sub_cate['sub']?sub_cate['sub']['sub_name'] : ''
                        sub['sort']=sub_cate['sub']?sub_cate['sub']['sort'] : 0;
                        if(sub_cate['sub']&&sub_cate['sub'][key+'s']&&sub_cate['sub'][key+'s'].length>0){
                            
                            tmp['sub_have_'+key+"s"]=1
                        }
                        tmp['sub_list'].push(sub);                           
                    })
                }

                console.log(tmp['sub_have_'+key+"s"])
                if(tmp&&tmp['sub_list']&&tmp['sub_list'].length>0){
                    tmp['sub_list'].sort(function(sub1,sub2){
                        return sub2['sort']-sub1['sort']
                    })
                }
                
                if(tmp['sub_have_'+key+"s"]==0){
                    tmp['sub_list']=[];
                }
                tmp[key+'_list']=[];
                if(category[key+'s']&&category[key+'s'].length>0){
                    category[key+'s'].forEach(key_model=>{
                        let obj=ctx.helper.assign_basic({},key_model);
                        tmp[key+'_list'].push(obj)
                    })
                }
                if(tmp['sub_have_'+key+"s"]!=0||tmp[key+'_list'].length>0){
                    list.push(tmp);
                }
                tmp=null
            });


            return list 
        } catch (error) {
            
        }
        return [];
    }
    /**
     * 
     * @param Model 
     * @param query 
     * @param condition 
     * @param key 
     * 产品类型列表(通用)
     * 过程：
     * 查询所有产品，遍历产品取出类型列表数据，遍历类型列表，删选子类型列表，
     * 返回类型列表数据
     */
    async product_cate_list(Model,query,condition,key){
        const{app}=this;
        try {
            const {Category,SubCategory,Sub} = app.model;
            console.log(query,condition,key);
            //改成按产品展示
            let result=await Model.findAll({
                include:[
                    {
                        model:Category,
                        association:Model.belongsTo(Category,{foreignKey:'category_id'}),
                        include:[{
                            model:SubCategory,
                            association:Category.hasMany(SubCategory,{foreignKey:'category_id'}),
                            include:[{
                                model:Sub,
                                association:SubCategory.belongsTo(Sub,{foreignKey:'sub_id'})
                            }]
                        }]
                    }
                ]
            })
            result=JSON.parse(JSON.stringify(result));
            if(!result||!Array.isArray(result)){
                return [];
            }
            let category_list:object[]=[];
            for(let i=0;i<result.length;i++){
                
                let product=result[i];
                if(product['category']&&product['category']['category_id']){
                    if(Array.isArray(product['category']['sub_categories'])&&product['category']['sub_categories'].length>0){
                        product['category']['sub_categories'].forEach(sub_cate=>{
                            if(sub_cate&&sub_cate['sub']){
                                sub_cate['sub_name']=sub_cate['sub']['sub_name']
                                delete sub_cate['sub'];
                            }
                        }) 
                    }
                    product['category']['sub_list']=product['category']['sub_categories'] ? product['category']['sub_categories'] :[];  
                    delete product['category']['sub_categories']
                    console.log("filter",category_list.filter(cate=>{cate['category_id']==product['category_id']}).length<=0)
                    let index=category_list.findIndex(cate=>{return cate['category_id']==product['category_id']})
                    
                    console.log()
                    if(index<0){
                        category_list.push(product['category']);
                    }
                    delete product['category']
                }
            }
            category_list.map(cate=>{
                let sub_list:object[]=cate['sub_list'];
                let sub_list1:object[]=[]
                let product_list=result.filter(p=>{
                    if(p['category_id']==cate['category_id']){
                        if(p['sub_id']&&sub_list1.filter(e=>{return e['sub_id']==p['sub_id']}).length<=0){
                            sub_list.filter(sub=>{
                                if(sub['sub_id']==p['sub_id']){
                                    sub_list1.push(sub)
                                }
                            })
                        }
                        return true 
                    }
                })
                cate[key+'_list']=product_list;   
                cate['sub_list']=sub_list1;

                if(cate['sub_list']&&cate['sub_list'].length>0){
                    cate['sub_have_'+key+"s"]=1
                }else{
                    cate['sub_have_'+key+"s"]=0
                }
            });
            //console.log("category:",category_list);
            return category_list;       
        } catch (error) {
            
        }
        return []
    }
    /**
     * 
     * @param Model 
     * @param key 
     * @param sort 
     * @param id 
     * 上移 弃用
     */
    async move_up(Model,key,sort,id){
        const {ctx}=this;
        try {
            let key_id=key+"_id";
            if(sort<=1){
                return ctx.helper.error_result("当前位置已经为第一个")
            }
            //查询上一个位置的数据，
            let up_result=await Model.findOne({where:{sort:sort-1}});
            //修改当前数据位置为上一个
            let condition={};
            condition[key_id]=id;
            await Model.update({sort:sort-1},{where:condition})
            //修改上一个的为当前位置
            condition[key_id]=up_result[key_id];
            await Model.update({sort:sort},{where:condition})
            return ctx.helper.success_result("上移成功")
        } catch (error) {
            
        }
        return ctx.helper.error_result("上移出现异常")
    }
    //下移
    /**
     * 
     * @param Model 
     * @param key 
     * @param sort 
     * @param id 
     * 下移 弃用
     */
    async move_down(Model,key,sort,id){
        const {ctx}=this;
        try {
            let key_id=key+"_id";
            let total=await Model.count();
            if(sort>=total){
                return ctx.helper.error_result("当前位置已经为最后一个")
            }
            //查询上一个位置的数据，
            let up_result=await Model.findOne({where:{sort:sort-1}});
            //修改当前数据位置为上一个
            let condition={};
            condition[key_id]=id;
            await Model.update({sort:sort-1},{where:condition})
            //修改上一个的为当前位置
            condition[key_id]=up_result[key_id];
            await Model.update({sort:sort},{where:condition})
            return ctx.helper.success_result("上移成功")
        } catch (error) {
            
        }
        return ctx.helper.error_result("上移出现异常")
    }
    //移动排序
    /**
     * 
     * @param model_name 模型名称
     * @param key 
     * @param sort 
     * @param id 
     * 互换位置 
     * 过程，根据当前位置字段sort查询当前元素，判断是否符合移动条件
     * 比如第一个上移。最后一个想下移动等，两者次序位置相等。
     * 根据目标位置获取目标元素，分别修改当前元素和目标元素，返回结果
     */
    async sort_move(mode_name,cur_pos,move_to_pos){
        const {ctx,app}=this;
        try {
            console.log(mode_name)
            let Model=app.model[ctx.helper.first_char_upper(mode_name)];
            let key_id=mode_name+"_id";
            let cur_result=await Model.findOne({where:{sort:cur_pos}})
            if(!cur_pos){
                return ctx.helper.error_result("没有指定可移动的次序")
            }
            if(!move_to_pos){
                return ctx.helper.error_result("当前已经在第一个或最后一个无法移动了")
            }
            if(cur_pos==move_to_pos){
                return ctx.helper.error_result("当前次序和目标次序一致，无法移动")
            }
            if(cur_pos<move_to_pos){//
             let count=await Model.count({where:{sort:{[Op.gt]:cur_pos}}})   
             if(count<=0){
                return ctx.helper.error_result("当前记录位置已经为最大")
             }
            }
            if(cur_pos>move_to_pos){//
                let count=await Model.count({where:{sort:{[Op.lt]:cur_pos}}})   
                if(count<=0){
                   return ctx.helper.error_result("当前记录位置已经为最小")
                }
               }
            let move_to_result=await Model.findOne({where:{sort:move_to_pos}})
            let condition={};
            condition[key_id]=cur_result[key_id]
            await Model.update({sort:move_to_pos},{where:condition});
            condition[key_id]=move_to_result[key_id]
            await Model.update({sort:cur_pos},{where:condition});    
            return ctx.helper.success_result("移动成功")
        } catch (error) {
            console.log(error)
        }
        return ctx.helper.error_result("移动次序异常")
    }
    /**
     * 
     * @param Model 
     * @param key 
     * @param sort 
     * @param id 
     * 同步位置数据
     * 过程：
     *  将需要排序的表中sort字段重置，从1开始
     */
    async sync_sort(tables){
        const{app,ctx}=this;
        try {
            let len=tables.length;
            for(let i=0;i<len;i++){
                let table_name=tables[i];
                let mode_name=ctx.helper.first_char_upper(table_name);
                //console.log(mode_name);
                let all_result=await app.model[mode_name].findAll();
                
                let count=all_result  ? all_result.length : 0;
                if(count>0){
                    for(let j=0;j<count;j++){
                        let m_reuslt=all_result[j];
                        if(m_reuslt&&m_reuslt[table_name+"_id"]){
                            let condition={};
                            condition[table_name+"_id"]=m_reuslt[table_name+"_id"];
                            await app.model[mode_name].update({sort:j+1},{where:condition})
                        }
                    }   
                }
            }   
            return ctx.helper.success_result("操作成功") 
        } catch (error) {
            console.log(error)
        }
        return ctx.helper.error_result("排序失败") 
    }
}